package cn.hrc.config;


import cn.hrc.utils.JwtUtil;
import cn.hrc.utils.PackJson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class JwtAuthenFilter extends BasicAuthenticationFilter {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private RedisTemplate redisTemplate;
    public JwtAuthenFilter(RedisTemplate redisTemplate,AuthenticationManager authenticationManager) {
        super(authenticationManager);
        this.redisTemplate = redisTemplate;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain)
            throws IOException, ServletException {

        logger.debug("授权过滤器 - 获取 Token 创建 认证成功对象");
        String bearer_token = request.getHeader("Authorization");
        logger.debug("\nAuthorization = " + bearer_token);

        if (bearer_token == null || (!bearer_token.startsWith("Bearer"))) {
            logger.info("第一种情况 没有 Token 可以访问/api/public");
            logger.info("无需产生 认证对象【账号，权限】 直接放行");
            chain.doFilter(request, response);
            return;
        }
        String token = bearer_token.substring(7);
        logger.info("token = " + token);
        // Redis 获取用户角色
        String tokenRedis = (String) redisTemplate.opsForValue().get("token:" + token);
        logger.info("tokenRedis:\t"+tokenRedis);
        logger.info("第二种情形：有Token 校验 Token");
        if (JwtUtil.isValid(tokenRedis)  == false){
            logger.info("Token 不在有效期");
            response.setStatus(403);
            response.setContentType("application/json;charset=utf-8");
            String ret = PackJson.pack(403,"Token 非法","").toString();
            response.getWriter().write(ret);
            response.flushBuffer();
        }
        logger.info("第三种情形：合法Token 创建 Authentication 对象 成功登录对象");
        logger.info("从 Token获取 账号 用户权限 去创建一个 Authentication 成功登录对象");
        String username = JwtUtil.getUsername(tokenRedis);
        logger.info("username:\t"+username);

        List<String> roles = JwtUtil.getRoles( tokenRedis);
        /** */
        List<SimpleGrantedAuthority> list = new ArrayList<>();
        for (String role : roles) {
            list.add(new SimpleGrantedAuthority(role));
        }
        /** */
        User user = new User(username, "", list);
        logger.info(user.toString());
        /** */
        logger.info("造一个 成功登录的用户对象  必须有账号和权限");
        UsernamePasswordAuthenticationToken authentication =
                new UsernamePasswordAuthenticationToken(user, null, list);
        logger.info("把成功登录的伪造对象" +
                "放在 类似 Session 的结构 SecurityContextHolder");
        SecurityContextHolder.getContext().setAuthentication(authentication);
        /** 每次业务请求
         * 把成功登录的用户信息放在 SecurityContextHolder */
        chain.doFilter(request, response);
    }
}
